home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Tool Chest / Development Platforms / Macintosh Common Lisp Related / User Contributions / print-u.lisp < prev    next >
Encoding:
Text File  |  1994-06-20  |  81.5 KB  |  2,021 lines  |  [TEXT/CCL2]

  1. (in-package :ccl)
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;; print-u.lisp
  4. ;;
  5. ;; Copyright  1992,1993, 1994 University of Toronto, Department of Computer Science
  6. ;; All Rights Reserved
  7. ;;
  8. ;; author: Mark A. Tapia markt@dgp.toronto.edu or markt@dgp.utoronto.ca
  9. ;;
  10. ;; print-u is a package for printing windows and documents. 
  11. ;; The following methods and functions are exported:
  12. ;;        get-printer-error     for returning the error condition or nil (no error)
  13. ;;        page-size             point indicating the page size used for printing
  14. ;;        picture-hardcopy      for quickdraw pictures
  15. ;;        print-contents        for drawing the nested views of a window
  16. ;;        view-print-contents   for printing a series of views
  17. ;;        scale-line-width      sets the scaling factor for line width for PostScript devices
  18. ;;        normal-line-width     sets PostScript line width to (1 1)
  19. ;;        set-print-reduction   sets the enlargement/reduction percentage between min and max
  20. ;;        get-print-reduction   returns the integer corresponding to the percentage 
  21. ;;                              enlargement/reduction
  22. ;;        set-print-orientation sets the print orientation to :portrait or landscape
  23. ;;        get-print-orientation returns the print orientation of either :portrait or landscape
  24. ;;        get-print-page        returns the page rectangles for the prec fields
  25. ;;
  26. ;; Internal (unexported) routines of interest
  27. ;;        document-hardcopy    for printing a general document
  28. ;;        window-hardcopy      for printing the contents of a window using
  29. ;;                             print-contents
  30.  
  31. ;;                             Routines that handle public and private print records
  32. ;;        check-print-prec     retrieves and validates the print record (get-print-prec object)
  33. ;;        default-prec         creates a default private print record
  34. ;;        get-prec             retrieves (and possibly creates) a print record for an object
  35. ;;        get-print-prec       calls get-prec on the outermost containing view
  36. ;;        prec-get             retrieves a print record for an object
  37. ;;        prec-put             associates a print-record with an object
  38. ;;        remove-prec          removes a print-record associated with an object
  39. ;;        remove-hc-prec       removes the public print-record
  40. ;;        replace-prec         replaces the print record associated with the object
  41. ;;                             only if it is different
  42. ;;        update-file-prec     saves a copy of a private print record in a resource 
  43. ;;        view-file-name       the pathname of the file associated with an object
  44. ;;
  45. ;; Acknowledgements:
  46. ;;     This code is based on print-utils.lisp written by DEH 6/20/91 and
  47. ;;     based on hardcopy.lisp with copyright 1988-89 Apple Computer, Inc. 
  48. ;;     The print-utils code has been modified to work in MCL2.0 and
  49. ;;     to print the contents of other views and to support generalized printing.
  50. ;;
  51. ;;     This code also uses the with-view-font and with-pen-state macros
  52. ;;     from oodles-of-utils:quickdraw-u.lisp by Michael S. Engber.
  53. ;;     Copyright  1991 Northwestern University Institute for the Learning Sciences
  54. ;;     All Rights Reserved.
  55. ;;
  56. ;;     Support for private print records was based on suggestions by Gregory
  57. ;;     Wilcox. The ideas were refined by Bill St. Clair.
  58. ;;
  59. ;;     Support for the setLineWidth PostScript command based on suggestions
  60. ;;     by Kemi Jona.
  61. ;;
  62. ;;     Changes to support Apple ImageWriters were suggested by
  63. ;;     Walker Sigismund, with help from Bill St. Clair.
  64. ;;
  65. ;;     Changes to support the LaserWriter 8 are the result of reports by users.
  66. ;;     Bill St. Clair found the bug and made the changes to save and restore
  67. ;;     the print record flags. The changes are marked with ***bill.
  68. ;;
  69. ;; Update history:
  70. ;;  1992-06-07  Added page-size method for retrieving the page size
  71. ;;  1992-10-27  Addeed support for private print records stored with the
  72. ;;              file in the resource fork (:type :prec :resource-id 128).
  73. ;;  1993-02-08  Added support for setLineWidth for PostScript lines.
  74. ;;              Replaced (require :QuickDraw) with macro with-rectangle-arg 
  75. ;;              and function setup-rect, if not present.
  76. ;;  1993-08-14  Added macro with-saved-gworld and modified with-open-document
  77. ;;              to suppport the ImageWriter.
  78. ;;  1993-12-21  Added functions to specify page setup parameters without calling
  79. ;;              pageSetup. The functions control enlargement/reduction and
  80. ;;              the orientation (portrait/landscape).
  81. ;;  1994-06-17  Modifications to support LaserWriter 8.1.1. Problems occured
  82. ;;              since the new laserWriter interacts in subtle ways. In particular,
  83. ;;              the new driver changes the (href ,pRec :tprint.prflag1.flags) 
  84. ;;              during the calls to the #_prJobMerge and #_prJobDialog trap calls.
  85. ;;              The new driver displays its own print progress dialog box, obviating
  86. ;;              the need. However, it does need to say press command-period to cancel.
  87. ;;              The version of print-u does not display a print progress dialog box.
  88. ;;              It will, however accept the cancel command (command-period) to
  89. ;;              cancel printing after completing the print job dialog.
  90. ;;              The printing stops after completing a full page for non-fred windows.
  91. ;;
  92. ;; NOTE: Every window has a private print record which controls the
  93. ;;       way the window will be printed and the attributes in the
  94. ;;       print-style-dialog box. The private print record is stored in the
  95. ;;       resource fork of the file when it is saved (:type :prec :resource-d 128)
  96. ;;       and when the Page Setup method is selected.
  97. ;;       The private print record is restored when the file is edited again.
  98. ;;       
  99. ;;       Every specific view uses the private print record of the outermost
  100. ;;       view containing the specific view.
  101. ;;
  102. ;;       A private print record of a window is saved when the window
  103. ;;       is saved (using Save, Save As, or Save Copy As and when the
  104. ;;       window is closed and needs to be saved. Methods are defined
  105. ;;       for fred windows.
  106. ;;
  107. ;;       For all other windows, you must provide a method for saving
  108. ;;       the file (ccl::window-save using ccl::window-file-save which
  109. ;;       must return the pathname) and a method for (view-file-name window)
  110. ;;        
  111. ;;       When a titled fred-window is saved (using the file menu
  112. ;;       items "save", "Save As ..." "Save Copy As..."), the page 
  113. ;;       setup attributes are saved in a print record in the file. 
  114. ;;       The record is placed in the :prec resource with id 128.  
  115. ;;       When the file is reopened in a fred-window, the page setup 
  116. ;;       attributes are restored.
  117. ;;    
  118. ;;
  119. ;;       Every other object uses a shared, public print record *print-hc-prec*.
  120. ;;       This print record is initialized at the beginning of a session.
  121. ;;
  122. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  123. ;;
  124. ;; Warnings:
  125. ;;     1. If you are running MCL2.0b1p3 or earlier, you must remove
  126. ;;        the semi-colons from before the (pushnew ...) form below.
  127.  
  128. ;;(pushnew :not-mcl-final *features*)
  129.  
  130. ;;
  131. ;;     2. This code will only work if the records definitions in the
  132. ;;        library;interfaces:printTraps.lisp are correct. 
  133. ;;        See the note below.
  134. ;;
  135. ;;     3. The code has been tested with LaserWriters but has not
  136. ;;        been tested with ImageWriters, StyleWriters etc. The routines
  137. ;;        use standard quickdraw calls.
  138. ;;
  139. ;;     4. This code changes the File menu-items for Page Setup and Print.
  140. ;;        The Page Setup menu item is changed to a window-menu-item and
  141. ;;        the associated menu-item action is #'ccl::page-setup. 
  142. ;;        Changing the page setup for a window does not affect
  143. ;;        other windows.
  144. ;;        
  145. ;;     5. Printing can only be cancelled by pressing Command-period.
  146. ;;        Printing cannot be stopped while the current page is being
  147. ;;        printed. but will be stopped before printing the next page.
  148. ;;  
  149. ;;     6. Due to a bug in background printing, we cannot display the
  150. ;;        current page being printed under certain conditions.
  151. ;;        When the print monitor is displaying the status of printing
  152. ;;        (with background printing off), (event-dispatch) does not return.
  153. ;;        As a result, the print progress dialog box does not indicate the
  154. ;;        page number of the page being printed.
  155. ;;        This problem disappears with the LaswerWriter8 driver.
  156. ;;
  157. ;;     7. The internal code for printing a document runs without interrupts
  158. ;;        with the result that no other work can proceed until either
  159. ;;        the hardcopy routine returns (or aborts) or is cancelled by
  160. ;;        pressing command-period.
  161. ;;
  162. ;;     8. If you are using oodles-of-utils (the oou: package), and have
  163. ;;        loaded quickdraw-u, print-u redefines the with-pen-state and
  164. ;;        with-font-spec macros.
  165. ;;
  166. ;;     10.If you are not running the laswerwriter software 8.0 or later,
  167. ;;        comment the code below.
  168. (eval-when (eval load compile) (pushnew :laserwriter8 *features*))
  169. ;;         
  170. ;;
  171. ;;  Eight examples of using the package are included at the end of this file:
  172. ;;    five printing examples, for printing various objects:
  173. ;;    - a small window
  174. ;;    - a picture
  175. ;;    - a large window
  176. ;;    - a general document
  177. ;;    - a window with a view-draw-contents method that calls print-contents
  178. ;;    and two examples of using private print records
  179. ;;    - creating a file, changing its print record, saving it and restoring it.
  180. ;;    - developing a class of views that store a print record in a slot
  181. ;;    and one example that prints a picture with fractional line widths
  182. ;;
  183. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  184.  
  185. #|
  186. ;;---------------------------Note-------------------------------------
  187.  
  188. ****Warning****
  189. Before loading this file, evaluate
  190.     (record-length :TPrint)
  191. This should return 120.
  192.  
  193. If the record-length is not 120, the tprstl and tprxinfo records 
  194. in the file printTraps.lisp in interfaces folder in the library
  195. folder must be replaced by the following: 
  196.  
  197. (defrecord tprstl
  198.   (wdev :signed-integer)
  199.   (ipagev :signed-integer)
  200.   (ipageh :signed-integer)
  201.   (bport :signed-byte)
  202.   (feed :unsigned-byte))
  203.  
  204. (defrecord tprxinfo
  205.   (irowbytes :signed-integer)
  206.   (ibandv :signed-integer)
  207.   (ibandh :signed-integer)
  208.   (idevbytes :signed-integer)
  209.   (ibands :signed-integer)
  210.   (bpatscale :signed-byte)
  211.   (bulthick :signed-byte)
  212.   (buloffset :signed-byte)
  213.   (bulshadow :signed-byte)
  214.   (scan :unsigned-byte)
  215.   (bxinfox :signed-byte))
  216.  
  217. Perform the following steps to update the record definitions:
  218. 1. Replace the record definitions in the source file
  219.    library;interfaces:printTraps.lisp with the definitions above. 
  220. 2. Evaluate the following expression to rebuild the index files
  221.    (ccl::reindex-interfaces)
  222.    You will now be able to access the new record definitions.
  223. 3. Quit from MCL. To free up the cons space.
  224. 4. Startup MCL again.
  225.  
  226. ----------------------Exported routines------------------------
  227.  
  228. The following exported routines allow the user to change the 
  229. print style for windows. Changing a print style only affects the
  230. current session. The print styles are reset upon re-entering MCL
  231. and are not stored with the document. Changing the style for 
  232. a fred window only changes the style of all fred windows during
  233. the session. Similarly changing the style of a non-fred window 
  234. only changes the styles for all fred windows.
  235.  
  236. page-setup                              ; method
  237. Changes the print style for a window.
  238.  
  239. (page-setup fred-window)
  240. Same as selecting the file Page Setup menu item from the
  241. standard *file-menu*.
  242. Displays the page setup dialog box and allows the user to
  243. change the style attributes for printing the window
  244. but does not affect the style for printing other windows
  245. or documents.
  246.  
  247. (page-setup t)
  248. Displays the page setup dialog box and allows the user to
  249. change the style attributes for all items that do not have
  250. private print records.
  251.  
  252. page-size                              ; method
  253. Returns a point indicating the page size used for printing
  254. fred or non-fred windows. The page-size for a fred window 
  255. may be different from that of a non-fred window.
  256.  
  257. (page-size fred-window)
  258. (page-size t)
  259.  
  260. The following exported routines direct output to a printer or
  261. to a PostScript file.
  262.  
  263. picture-hardcopy                        ; function
  264. picture-hardcopy picture &optional show-dialog?
  265.   Directs the quickdraw picture to the printer
  266.     picture       a picture
  267.     show-dialog?  ignored
  268.  
  269.    If no printer errors occurred and the user did not cancel
  270.       returns nil
  271.    otherwise 
  272.       returns the non-zero print error code which caused the termination
  273.  
  274. print-contents                          ; method
  275. print-contents view &optional (offset #@(0 0))
  276. Executes the quickdraw commands for drawing the contents of a view.
  277.  
  278. When offset is #@(0 0), uses local coordinates for drawing,
  279. otherwise adjusts coordinates by subtracting offset from coordinates.
  280.  
  281. Print-contents supports the following types of views:
  282.     window                    - draws a box around the content area
  283.                                 of the window and prints the contents
  284.                                 of the subviews.
  285.  
  286.     static-text-dialog-item   - draws a box around the item
  287.                                 and prints the text with the view font
  288.  
  289.     editable-text-dialog-item - draws a box around the item
  290.                                 and prints the text with the view font
  291.  
  292.     button-dialog-item        - draws the button and the text within
  293.  
  294.     view                      - prints the contents of the subviews
  295.  
  296.     sv                        - does nothing
  297.  
  298. get-printer-error                       ; function
  299. (get-printer-error)
  300. either returns nil or a printer-condition
  301. If nil, indicates no errors occurred during the last print request.
  302. Otherwise, returns the printer-condition with slots:
  303. phase - either $err-printer??? or nil
  304. code  - either the code returned from the printer operation or nil
  305. cond  - either nil or an error condition when not a printer error
  306.  
  307.  
  308.                                         ; PostScript
  309. -- PostScript routines --
  310. The scale-line-width and normal-line-width routines affect PostScript
  311. devices only. Use these commands in document-hardcopy or to create
  312. a picture printed by picture-hardcopy, when using a PostScript device.
  313.  
  314. For details on set-line-width and picture comments, see Mac Tech Notes #175
  315. (SetLineWidth Revealed) and #91 (Optimizing for the LaserWriter - Picture 
  316. Comments).
  317.  
  318. (scale-line-width scale)                ; function
  319. Sets the scale factor for the Postscript pen width, has no effect
  320. on QuickDraw devices.
  321.  
  322. Scale is the rational used for scaling the Quickdraw pen width
  323. For the thinest lines possible on a LaserWriter at Reduce/Enlarge=100%
  324.   (1) set the quickdraw pen width to #@(1 1)
  325.   (2) call (scale-line-width 1/4)
  326.  
  327. (normal-line-width)                     ; function
  328. Sets the scale factor to 1 for the Postscript pen width, has no effect
  329. on QuickDraw devices.
  330.  
  331. (set-print-reduction t percentage)      ; method
  332. Sets the print reduction/enlargement of the printer record associated
  333. with the object to the integer percentage. The percentage must be in
  334. the range specified by the izoomMin and :izoomMax fields of the tprint record.
  335.  
  336. (get-print-reduction t)                 ; method
  337. Returns the integer corresponding to the reduction/enlargement
  338. of the printer record associated with the object.
  339.  
  340. (set-print-orientation t orientation)   ; method
  341. Sets the orientation of the printer record associated with the object
  342. to orientation (either :portrait or :landscape)
  343.  
  344. (get-print-orientation t)               ; method
  345. Gets the orientation of the printer record associated with the object
  346. to orientation -- either :portrait or :landscape.
  347.  
  348. (get-print-page t)                      ; method
  349. Returns as values the points corresponding the rectangles for
  350. the various print page boundaries.
  351.  
  352.  
  353. ----------------------Unexported routines------------------------
  354.  
  355. Window-hardcopy prints the contents of a window.
  356. Specialize if you want to acheive different effects for
  357. other kinds of windows.
  358.  
  359. Use view-print-contents to initiate the printing of a view
  360. and all of its subviews.
  361.  
  362. Use the print-contents methods as the basis for developing
  363. methods for other types of views.
  364.  
  365. Document-hardcopy is a general routine that forms the basis
  366. for other print routines. Call this routine if you want
  367. to develop your own custom printing functions fo documents
  368. and windows.
  369.  
  370. window-hardcopy                         ; method
  371. window-hardcopy (window window) &optional (show-dialog? t)
  372.    Prints the window, The show-dialog? parameter is present
  373.    for compatibility with the standard method for fred-windows
  374.    and is used to display the print job dialog.
  375.    
  376.    The basic routine calls print-contents on the window, which
  377.    repeatedly calls print-contents on the views and subviews.
  378.  
  379.    If no printer errors occurred and the user did not cancel
  380.       returns t
  381.    otherwise 
  382.       returns nil indicating an error occurred in printing
  383.  
  384.     Parameters
  385.       window           the window to be printed
  386.        show-dialog?    display the print job dialog (default t)
  387.  
  388.  
  389. document-hardcopy                       ; not exported
  390. document-hardcopy  print-fn compute-doc-size &key view (show-dialog? t)
  391.    Prints a document. The show-dialog? parameter is present
  392.    for compatibility with the standard method for printing 
  393.    fred-windows and is used to display the print job dialog.
  394.  
  395.    This routine is the basis for picture-hardcopy and window-hardcopy.
  396.    Use document-hardcopy to build other specialized hardcopy routines.
  397.  
  398.    If no printer errors occurred and the user did not cancel
  399.       returns t
  400.    otherwise 
  401.       returns nil indicating an error occurred in printing
  402.  
  403.    The routine performs the following sequence of operations
  404.    1. Opens the printer
  405.    2. Displays the print job dialog box which indicates the method for cancelling.
  406.    3. Retrieves the print record
  407.    4. Determines the page layout using the rectangle corners
  408.       returned by the document-corners function
  409.    5. Opens the printer document
  410.    6. While there are pages to print and the user has not pressed cancel
  411.          For each page in the document that is to be printed, repeats the 
  412.          following steps
  413.             a. opens the page
  414.             b. draws the page using the print-fn
  415.             c. closes the page
  416.    7. Closes the printer document
  417.    8. Closes the printer
  418.    9  If no printer errors occurred and the user did not cancel
  419.          returns t
  420.       otherwise 
  421.          returns nil indicating an error occurred in printing
  422.       Use (get-printer-error) to retrive the printer error condition.
  423.  
  424.     Parameters
  425.     document-corners 
  426.                   Function that computes the corners of the document
  427.                   Parameters:
  428.                        view         the view associated with the document
  429.                        page-size    a point representing the size of the
  430.                                     page-rectangle in pixels
  431.                   Returns the corners of the document rectangle
  432.                   Where the default points are #@(0 0) page-size
  433.                        topleft      the top left corner
  434.                        bottomRight  the bottom right corner
  435.                   If document-corners is not a function, uses the routine
  436.                   default-document-corners which returns the points defining
  437.                   the page rectangle.
  438.  
  439.    print-fn       Function that draws a picture of the document.
  440.                   Parameters:
  441.                        view        suppled by the view keyword. This should be a view
  442.                                    or nil.
  443.                        page-size   the page rectangle size as a point (top left = #@(0 0))
  444.                        page-no     the current page being printed
  445.                        offset      the top left corner of the portion of the document
  446.                   If local, prints the rectangular portion of the document defined 
  447.                      by the points offset (add-points offset page-size). The
  448.                      coordinates are unchanged.
  449.                   Otherwise, adjusts the coordinates by subtracting offset
  450.                      from all points to print within the page rectangle #@(0 0)
  451.                      page-size.
  452.  
  453.                   If print-fn is not a function, uses default-document-hardcopy
  454.                   which does nothing.
  455.  
  456.    :view          the view, default is nil for no view. Passed as a parameter to
  457.                   document-corners and print-fn.
  458.  
  459.    :show-dialog?  display the print job dialog (default t)
  460.  
  461.    :local         default is t. If true, use the document coordinates while printing
  462.                   otherwise use coordinates within the page rectangle,
  463.                   by adjusting all coordinates by offset. 
  464.  
  465. |#
  466.  
  467. (export '(picture-hardcopy print-contents page-setup get-printer-error page-size
  468.           set-print-reduction get-print-reduction set-print-orientation
  469.           get-print-orientation get-print-page))
  470.  
  471. (provide 'print-u)
  472.  
  473.  
  474.  
  475. ;; prepare to redefine the functions get-prec and remove-prec by a standard generic function
  476. (progn
  477.   (when (and (fboundp 'get-prec) 
  478.              (equal (type-of #'get-prec) 'function))
  479.     (fmakunbound 'get-prec))
  480.   (when (and (fboundp 'remove-prec)
  481.              (equal (type-of #'get-prec) 'function))
  482.     (fmakunbound 'remove-prec))
  483.   (setq *save-exit-functions*
  484.         (remove 'remove-prec *save-exit-functions* :key #'function-name)))
  485.  
  486. (eval-when (eval load compile)
  487.   (require :resources))
  488.  
  489. #-not-mcl-final 
  490. (eval-when (eval compile) 
  491.   (require :quickDraw))
  492. #+not-mcl-final
  493. (eval-when (eval compile) 
  494.   (ccl::require-interface :printTraps)
  495.                                         ;(require :quickDraw) replaced by two macros below
  496.   (require :loop)                       ; loop is automatically included in MCL 2.0f
  497.   )
  498.  
  499.  
  500. ;; Routines from quickdraw-u.lisp from Michael S. Engber
  501. ;;     Copyright  1991 Northwestern University Institute for the Learning Sciences
  502. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  503.  
  504. (defparameter *full-debug* nil)         ; full debugging, prints all trap calls
  505.                                         ; change to t for full debugging information
  506.  
  507. ;; use this definition if you want full debugging
  508. (defmacro call-trap (flag trap &rest args)
  509.   `(progn
  510.      (when *full-debug*
  511.      (format t " (trap ~a " ,flag))
  512.      (prog1
  513.        (require-trap ,trap  . ,args)
  514.        (when *full-debug*
  515.          (format t "--> ~a) " ,flag)))))
  516.  
  517. ;; the following macros are standard in MCL2.0 final
  518. #+not-mcl-final 
  519. (eval-when (:compile-toplevel :load-toplevel :execute)
  520.   
  521.   (unless (fboundp 'href)
  522.     (defmacro href (pointer accessor)
  523.       `(rref ,pointer ,accessor :storage :handle)))
  524.   
  525.   (unless (fboundp 'pref)
  526.     (defmacro pref (pointer accessor)
  527.       `(rref ,pointer ,accessor :storage :pointer))))
  528.   
  529. (eval-when (:compile-toplevel :load-toplevel :execute)
  530.   (unless (fboundp 'hset)
  531.     (defmacro hset (pointer accessor thing)
  532.       `(rset ,pointer ,accessor ,thing :storage :handle)))
  533.   
  534.   (unless (fboundp 'pset)
  535.     (defmacro pset (pointer accessor thing)
  536.       `(rset ,pointer ,accessor ,thing :storage :pointer)))
  537.   
  538.   (unless (fboundp 'with-rectangle-arg)
  539.     ; add quickdraw support routines
  540.     (defmacro with-rectangle-arg ((var left &optional top right bottom) &body body)
  541.       "takes a rectangle, two points, or four coordinates and makes a rectangle.
  542. body is evaluated with VAR bound to that rectangle."
  543.       `(rlet ((,var :rect))
  544.          (setup-rect ,var ,left ,top ,right ,bottom)
  545.          ,@body))
  546.     
  547.     (defun setup-rect (rect left top right bottom)
  548.       (cond (bottom
  549.              (setf (pref rect rect.topleft) (make-point left top))
  550.              (setf (pref rect rect.bottomright) (make-point right bottom)))
  551.             (right
  552.              (error "Illegal rectangle arguments: ~s ~s ~s ~s"
  553.                     left top right bottom))
  554.             (top
  555.              (setf (pref rect rect.topleft) (make-point left nil))
  556.              (setf (pref rect rect.bottomright) (make-point top nil)))
  557.             (t (%setf-macptr rect left))))
  558.     )
  559.   
  560.   (unless (fboundp 'with-font-spec)
  561.     (defmacro with-font-spec (font-spec &body body)
  562.       (if (and (listp font-spec) (every #'constantp font-spec))
  563.         (multiple-value-bind (ff ms) (font-codes font-spec)
  564.           `(with-font-codes ,ff ,ms ,@body))
  565.         (let ((ff (gensym))
  566.               (ms (gensym)))
  567.           `(multiple-value-bind (,ff ,ms) (font-codes ,font-spec)
  568.              (with-font-codes ,ff ,ms ,@body))))))
  569.   
  570.   (unless (fboundp 'with-pen-state)
  571.     (defmacro with-pen-state ((&key pnLoc pnSize pnMode pnPat pnPixPat) &body body)
  572.       (let ((state (gensym)))
  573.         `(rlet ((,state :PenState))
  574.            (call-trap 'getPenState #_GetPenState :ptr ,state)
  575.            (unwind-protect
  576.              (progn
  577.                ,@(when pnLoc    `((call-trap 'moveTo #_MoveTo :long ,pnLoc)))
  578.                ,@(when pnSize   `((call-trap 'penSize #_PenSize :long ,pnSize)))
  579.                ,@(when pnMode   `((call-trap 'penMode #_PenMode :signed-integer ,pnMode)))
  580.                ,@(when pnPat    `((call-trap 'penPat #_PenPat :ptr ,pnPat)))
  581.                ,@(when pnPixPat `((call-trap 'penPixPat #_PenPixPat :ptr ,pnPixPat)))
  582.                ,@body)
  583.              (call-trap 'setPenState #_SetPenState :ptr ,state)))))))
  584. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  585. ;; end of macros from quickdraw-u.lisp
  586.  
  587. (defun set-page-range (prec pages-to-print)
  588.   (hset prec :tprint.prjob.iFstpage 1)
  589.   (hset prec :tprint.prjob.iLstpage pages-to-print))
  590.  
  591. (unless (fboundp 'copy-handle)
  592.   (defun copy-handle (handle)
  593.     (rlet ((h :pointer))
  594.       (setf (%get-ptr h) handle)
  595.       (call-trap 'handToHand #_HandToHand h)
  596.       (%get-ptr h)))
  597.   (export 'copy-handle))
  598.  
  599. (defvar *printing* nil "Printing not in progress")
  600. (defvar *print-record-window* nil "window containg the view being printed")
  601. (defvar *mcl-get-print-record* #'get-print-record)
  602. (defparameter *debug* nil)              ;  for debugging only
  603. (defparameter *full-debug* nil)         ;  for extensive debugging only
  604.  
  605. (defparameter *print-error* nil "The printing error in the form printer-condition")
  606. (defvar *print-hc-prec*)                ; the default print-record
  607.  
  608. ;; condition for printer errors
  609. (define-condition printer-condition (error)
  610.   (phase code cond)
  611.   (:report (lambda (condition stream)
  612.              (with-slots (phase code cond) condition
  613.                (if cond
  614.                  (format stream "Printer error ~s" cond)  
  615.                  (format stream "Printer error ~s in phase ~s" code phase))))))
  616.  
  617. ;; condition for a user-cancel for a print operation
  618. (define-condition user-cancel (printer-condition))
  619.  
  620.  
  621.  
  622. ;; functions for converting coordinates from one system to another
  623. (defun convert-offset (window container offset)
  624.   ;; If the container is a view, returns in window coordinates, 
  625.   ;; the point offset which is expressed in container coordinates
  626.   ;; Otherwise returns the offset.
  627.   (subtract-points 
  628.    (if container
  629.      (convert-coordinates #@(0 0) container window)
  630.      #@(0 0))
  631.    offset))
  632.  
  633. (defmethod window-view-corners ((self view) &optional (offset #@(0 0)))
  634.   ;; returns the coordinates of the view corners in window coordinates
  635.   ;; offset by offset
  636.   (let ((container (view-container self))
  637.         (window (view-window self)))
  638.     (multiple-value-bind (topLeft bottomRight)
  639.                          (view-corners self)
  640.       (setq offset (convert-offset window container offset))
  641.       (values (add-points topLeft offset) (add-points bottomRight offset)))))
  642.  
  643. (defmethod window-view-corners ((self dialog-item)  &optional (offset #@(0 0)))
  644.   ;; returns the coordinates of the view corners of a dialog item
  645.   ;; in window coordinates offset by offset
  646.   (let ((container (view-container self))
  647.         (window (view-window self)))
  648.     (multiple-value-bind (topLeft bottomRight)
  649.                          (view-corners self)
  650.       (setq offset (convert-offset window container offset))
  651.       (values (add-points topLeft offset) (add-points bottomRight offset)))))
  652.  
  653. ;;; Modified routines from print-utils.lisp for printing the contents of a views
  654. ;;; converted from MCL1.3.2
  655. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  656. ;;
  657. ;;hardcopy.lisp
  658. ;;
  659. ;;
  660. ;;copyright 1988-89 Apple Computer, Inc.
  661. ;;
  662. ;; defines a very basic printing routine for windows
  663. ;;
  664. ;; Code taken from Apple and Bill Kornfeld and played with a bit to get
  665. ;; something working.  Trying to change the wptr and
  666. ;; then doing a view-draw-contents fails --- LISP unexpectantly quits.
  667. ;; view-draw-contents without changing the window pointer
  668. ;; causes a print job to be sent to the printer but nothing comes out.
  669. ;; Using a print-contents function that just makes the appropriate 
  670. ;; calls seems to work ok. The basic print-contents
  671. ;; quickdraw functions for text, views and windows are defined here. 
  672. ;; Some extra print-contents functions for other items is defined in
  673. ;; odin-printing.lisp -- DEH 6/20/91
  674.  
  675. ;;;------------------ Printer constants----------------------------------------
  676. (defconstant $err-printer 94)
  677. (defconstant $err-printer-load 95)
  678. (defconstant $err-printer-start 97)
  679.  
  680. ;;;------------------ Picture comment operand ---------------------------------
  681. (defconstant $set-line-width 182 "Picture comment for setting line width")
  682.  
  683. ;;;------------------ Routine for trapping printer errors----------------------
  684. (defun printer-ok (&optional (errnum $err-printer)
  685.                              &aux (print-error (call-trap 'prError #_prError)))
  686.   ;; Checks for a printer error for the last printer command
  687.   ;; If there was an error, sets *printing* to nil
  688.   ;;   and if there has not been a previous printing error
  689.   ;;   sets the *print-error* to `(,errnum ,error)
  690.   (if (zerop print-error)
  691.     t
  692.     (progn
  693.       (unless *print-error*
  694.         (setq *print-error* (make-condition 'printer-condition))
  695.         (setf (slot-value *print-error* 'phase) errnum
  696.               (slot-value *print-error* 'code) print-error
  697.               (slot-value *print-error* 'cond) nil))
  698.       (setq *printing* nil)
  699.       (signal 'user-cancel))))
  700.  
  701. (defmacro check-printer-ok (form &optional (errnum $err-printer))
  702.   "Checks that the printer is ok after the execution of the form"
  703.   `(progn
  704.      ,form
  705.      (if (printer-ok ,errnum)
  706.        t
  707.        (throw :cancel nil))))
  708.  
  709. (defun get-printer-error ()
  710.   ;; returns nil or the the last non-zero printer error 
  711.   *print-error*)
  712.  
  713. ;;;------------------ The basic print-contents functions-----------------------
  714. (defmethod print-contents ((v window) &optional (offset #@(0 0)))
  715.   "a window draws a box around itself and
  716.    then asks its subviews to print themselves"
  717.   ;;first frame it
  718.   (multiple-value-bind (top-left bottom-right)
  719.                        (window-view-corners v offset)
  720.     (ccl::with-rectangle-arg (r top-Left bottom-right) 
  721.       (call-trap 'frameRect #_FrameRect r)))
  722.   (dovector (sv (view-subviews v))
  723.     (print-contents sv offset)))
  724.  
  725. (defmethod print-contents ((v view) &optional (offset #@(0 0)))
  726.   "a view just asks its subviews to print themselves"
  727.     (dovector (sv (view-subviews v))
  728.       (print-contents sv offset)))
  729.  
  730. (defmethod print-contents ((sv ccl::basic-editable-text-dialog-item)
  731.                            &optional (offset #@(0 0)))
  732.   "editable text uses textbox -- takes into account font and the justification"
  733.     (multiple-value-bind (top-left bottom-right)
  734.                          (window-view-corners sv offset)
  735.     (with-font-spec (view-font sv)
  736.       (ccl::with-rectangle-arg (r top-Left bottom-right)
  737.         (with-pstrs ((pstring (dialog-item-text sv)))
  738.           (call-trap 'textBox #_TextBox :ptr (%inc-ptr pstring 1)
  739.            :long (length (dialog-item-text sv))
  740.            :ptr r
  741.            :word (slot-value sv 'ccl::text-justification)))))))
  742.  
  743. (defmethod print-contents ((sv static-text-dialog-item) &optional (offset #@(0 0)))
  744.   "static text uses textbox -- take into account font and the justification"
  745.   (multiple-value-bind (top-left bottom-right)
  746.                        (window-view-corners sv offset)
  747.     (with-font-spec (view-font sv)
  748.       (ccl::with-rectangle-arg (r top-Left bottom-right)
  749.         (with-pstrs ((pstring (dialog-item-text sv)))
  750.           (call-trap 'textBox #_TextBox :ptr (%inc-ptr pstring 1)
  751.            :long (length (dialog-item-text sv))
  752.            :ptr r
  753.            :word (slot-value sv 'ccl::text-justification)))))))
  754.  
  755. (defmethod print-contents ((sv button-dialog-item)  &optional (offset #@(0 0)))
  756.   (multiple-value-bind (top-left bottom-right)
  757.                        (window-view-corners sv offset)
  758.     (ccl::with-rectangle-arg (r top-left bottom-right)
  759.       (with-font-spec (view-font sv)
  760.         (with-pstrs ((pstring (dialog-item-text sv)))
  761.           (call-trap 'textBox #_TextBox :ptr (%inc-ptr pstring 1)
  762.            :long (length (dialog-item-text sv))
  763.            :ptr r :word 1)))
  764.       ;;; end of with-font-spec
  765.       (with-pen-state (:pnSize #@(1 1)
  766.                                :pnMode #$PATOR
  767.                                :pnPat *black-pattern*)
  768.           (decf (rref r :rect.left)
  769.                 (floor (dialog-item-width-correction sv) 2))
  770.           (incf (rref r :rect.right)
  771.                 (floor (dialog-item-width-correction sv) 2))
  772.           (call-trap 'frameRoundRect #_FrameRoundRect :ptr r :word 10 :word 6)))))
  773.  
  774. (defmethod print-contents ((sv simple-view) &optional offset)
  775.   (declare (ignore offset))
  776.   "default if all else fails do nothing"
  777.   t)
  778. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  779. ;;; End of modified routines from print-utils.lisp
  780.  
  781. ;;;------------------ handles - checking validity and removing -------------------
  782. (unless (fboundp 'valid-handle)
  783.   (defun valid-handle (handle)
  784.     (when (and handle
  785.                (handlep handle)
  786.                (pointerp handle)
  787.                (macptrp handle)
  788.                (not (equal handle (%null-ptr))))
  789.       handle)))
  790.  
  791. (defun dispose-handle (handle)
  792.   (when (valid-handle handle)
  793.       (call-trap 'disposeHandle #_disposeHandle handle)))
  794.  
  795. ;;;---------retrieving and changing the value of an internal print-record---------
  796. ;; routines do not allocate new print records 
  797. (defmethod prec-get ((self view))
  798.   (view-get self :prec))
  799.  
  800. (defmethod prec-get ((self t))
  801.   (when (boundp '*print-hc-prec*)
  802.     *print-hc-prec*))
  803.  
  804. (defmethod prec-put ((self view) value)
  805.   (view-put self :prec value))
  806.  
  807. (defmethod prec-put ((self t) value)
  808.   (setq *print-hc-prec* value))
  809.  
  810. (defmacro clean-catch-cancel (flag &body body)
  811.   ;; When debugging print the flag
  812.   ;; Execute the body unwind-protected while catching
  813.   ;; cancels, errors, aborts and breaks
  814.   (let ((old-state (gensym)))
  815.    `(let ((,old-state *break-on-errors*))
  816.      (unwind-protect
  817.       (handler-case
  818.        (restart-case
  819.          (catch :cancel
  820.            (when *debug* (format t "~&--->~a~%" ,flag))
  821.            (setq *break-on-errors* nil)
  822.            ,@body)
  823.          (abort () (message-dialog "Printing aborted.")
  824.                 (stop-printing))
  825.          (error (condition) (stop-printing condition)))
  826.        (error (condition) (setq *printing* nil) condition))
  827.       (setq *break-on-errors* ,old-state)))))
  828.  
  829. ;;;---------determining the window containing the view (if any)---------
  830. ;;  for views returns
  831. ;;    either the window containing the view
  832. ;;    or the outermost view containing the view
  833. ;;  for all other objects returns the object
  834.  
  835. (defmethod containing-window ((view window))
  836.   view)
  837.  
  838. (defmethod containing-window ((sub-view view))
  839.   (loop with new-view
  840.         do (setq new-view (view-container sub-view))
  841.         while new-view
  842.         do (setq sub-view new-view)
  843.         finally (return sub-view)))
  844.  
  845. (defmethod containing-window ((self t))
  846.   self)
  847.  
  848. ;;;---------allocating, modifying and updating the internal print records---------
  849. (defmethod remove-view-from-window :after ((subview view))
  850.   (remove-prec subview))
  851.  
  852. ;; file names associated with views
  853. (defmethod view-file-name ((window fred-window))
  854.   (slot-value window 'ccl::my-file-name))
  855.  
  856. (defmethod view-file-name ((self t))
  857.   nil)
  858.  
  859. ;;;---------manipulating the internal print records---------
  860. (defmethod remove-prec ((self t))
  861.   ;; clean up the internal tprint handle (if any)
  862.   (dispose-handle (prec-get self))
  863.   (prec-put self nil))
  864.  
  865. (defmethod replace-prec ((self t) new-value)
  866.   ;; clean up the internal tprint handle (if any)
  867.   (let ((old-value (prec-get self)))
  868.     (unless (eq old-value new-value)
  869.       (remove-prec self)
  870.       (prec-put self new-value))
  871.     new-value))
  872.  
  873. (defmethod update-file-prec ((self t) prec &optional file-name)
  874.   ;; Saves a copy of the internal print record as a resource. 
  875.   ;; Called during a page setup and after saving a file (in this
  876.   ;; case the file-name argument is supplied 
  877.   (let ((filename (or file-name (view-file-name self)))
  878.         new-prec
  879.         old-prec)
  880.     (when (valid-handle prec)
  881.       (when (pathnamep filename)
  882.         (with-open-resource-file (refnum filename :if-does-not-exist :create)
  883.           (when *debug* (print-record prec :tprint) (terpri))
  884.           (setq old-prec (get-resource :prec 128 :errorp nil))
  885.           (when (valid-handle old-prec)
  886.             (remove-resource old-prec)
  887.             (dispose-handle old-prec))
  888.           (setq new-prec (copy-handle prec))
  889.           (when *debug* (print-record prec :tprint) (terpri))
  890.           ;; from Inside Macintosh I-123
  891.           (call-trap 'hNOpurge #_HNoPurge new-prec)
  892.           (add-resource new-prec :prec 128) 
  893.           (call-trap 'changedResource #_changedResource new-prec)
  894.           (write-resource new-prec)
  895.           (call-trap 'hPurge #_HPurge new-prec)
  896.           new-prec)))))
  897.  
  898. (defmethod get-prec ((self t))
  899.   (let (printer-record
  900.         (file-name (view-file-name self))
  901.         (view-print-record (prec-get self))
  902.         create)
  903.     ;; retrieves and possibly initializes the private print record
  904.     ;; if the print record exists and is a valid handle
  905.     ;;   returns the handle
  906.     ;; otherwise initializes the private print record
  907.     ;;   tries to read the :prec resource from the view-file-name
  908.     ;;    if successful
  909.     ;;     stores and returns a copy of the resource (handle)  
  910.     ;;    otherwise
  911.     ;;     creates a default print record using default-prec
  912.     ;;  
  913.     (cond 
  914.      ((valid-handle view-print-record) view-print-record)
  915.      ((null (pathnamep file-name)) (create-default-prec self))
  916.      (t (with-open-resource-file (refnum file-name :if-does-not-exist nil)
  917.           (cond 
  918.            ((or (null refnum) 
  919.                 (null (setq printer-record (get-resource :prec 128 :errorp nil))))
  920.             (setq view-print-record (create-default-prec self)
  921.                   create t))
  922.            (t (remove-prec self)
  923.               (setq view-print-record (copy-record printer-record :tprint))
  924.               (replace-prec self view-print-record)))
  925.           (when create
  926.             (update-file-prec self view-print-record))
  927.           view-print-record)))))
  928.  
  929. (defmethod create-default-prec ((self t))
  930.   (let (view-print-record)
  931.     (remove-prec self)
  932.     (setq view-print-record (default-prec self))
  933.     (replace-prec self view-print-record)
  934.     (update-file-prec self view-print-record)
  935.     view-print-record))
  936.  
  937. (defmethod get-print-prec ((self t))
  938.   (let ((outer-container (containing-window self)))
  939.     (cond ((null outer-container) (get-prec t))
  940.           ((eq self outer-container) (get-prec self))
  941.           (outer-container (get-prec outer-container))
  942.           (t (get-prec t)))))
  943.  
  944. ;; create a default print-record
  945. (defmethod default-prec ((self t))
  946.   (let (code
  947.         view-print-record)
  948.     (clean-catch-cancel 
  949.       :prec
  950.       (remove-prec self)
  951.       (setq view-print-record (call-trap 'newHandle #_NewHandle :errchk (record-length :TPrint)))
  952.       (setq code (call-trap 'memError #_MemError))
  953.       (when (zerop code)
  954.         (replace-prec self view-print-record)
  955.         (if (not (valid-handle view-print-record))
  956.           (setq code "invalid-handle")
  957.           (progn
  958.             (check-printer-ok (call-trap 'printDefault #_PrintDefault :ptr view-print-record))
  959.             (setq code nil)))))
  960.     (if code
  961.       (remove-prec self)
  962.       view-print-record)))
  963.  
  964.  
  965. ;; routines for allocating/deallocating the tprint handle for printing
  966.  
  967. (defun stop-printing (&optional condition)
  968.   ;; stop printing
  969.   (setq *printing* nil
  970.         *print-error* (make-condition 'printer-condition))
  971.   (if condition
  972.     (setf (slot-value *print-error* 'phase) nil
  973.           (slot-value *print-error* 'code) nil
  974.           (slot-value *print-error* 'cond) condition)
  975.     (setf (slot-value *print-error* 'phase) $err-printer
  976.           (slot-value *print-error* 'code) #$iPrAbort
  977.           (slot-value *print-error* 'cond) nil))
  978.   (call-trap 'prseterror #_PrSetError #$iPrAbort)
  979.   (error *print-error*))
  980.  
  981. (defun reset-printing ()
  982.   (setq *printing* nil)
  983.   (call-trap 'prseterror #_prSetError #$NoErr))
  984.  
  985. ;; the method for getting a fred print record
  986. (defmethod get-print-prec ((window fred-window))
  987.   (get-print-record))
  988.  
  989. (defmethod check-print-prec ((self t))
  990.   ;; gets the tprint handle and validates it 
  991.   ;; when successful, returns the tprint handle
  992.   ;; must be called when the printer is open (e.g. within with-printer-open)
  993.   (let ((local-prec (get-print-prec self)))
  994.     (when local-prec
  995.       (clean-catch-cancel 
  996.        :check-print
  997.        (check-printer-ok (call-trap 'prValidate #_prValidate :ptr local-prec :boolean))
  998.        local-prec))))
  999.  
  1000. #|                                      ; obsolete routines, replaced by LaserWriter8
  1001. ;; the print status dialog box (print-dialog) displayed when printing in progress.
  1002. (defclass print-dialog (window)
  1003.   ()
  1004.   (:default-initargs
  1005.     :window-type :double-edge-box 
  1006.     :view-position :centered 
  1007.     :view-size #@(373 96) 
  1008.     :close-box-p nil 
  1009.     :view-font '("Chicago" 12 :srcor :plain)))
  1010.  
  1011. #+laserwriter8 
  1012. (defmethod initialize-instance ((window print-dialog) &rest initargs)
  1013.   (apply #'call-next-method window initargs)
  1014.   (add-subviews window
  1015.                 (make-instance 'static-text-dialog-item
  1016.                   :view-position #@(10 10)
  1017.                   :view-size #@(151 40) 
  1018.                   :dialog-item-text (format nil
  1019.                                             "Printing in progress
  1020. To cancel press ~a-." #\CommandMark)
  1021.                   :view-nick-name 'title)
  1022.                 ))
  1023.  
  1024. #-laserwriter8 
  1025. (defmethod initialize-instance ((window print-dialog) &rest initargs)
  1026.   (apply #'call-next-method window initargs)
  1027.   (add-subviews window
  1028.                 (make-instance 'static-text-dialog-item
  1029.                   :view-position #@(10 10)
  1030.                   :view-size #@(151 40) 
  1031.                   :dialog-item-text (format nil
  1032.                                             "Printing in progress
  1033. To cancel press ~a-." #\CommandMark)
  1034.                   :view-nick-name 'title)
  1035.                 
  1036.                 (make-instance 'static-text-dialog-item 
  1037.                   :view-position #@(10 72) 
  1038.                   :view-size #@(120 18) 
  1039.                   :dialog-item-text "Printing page")
  1040.                 
  1041.                 (make-instance 'static-text-dialog-item 
  1042.                   :view-position #@(135 72) 
  1043.                   :view-size #@(36 18) 
  1044.                   :dialog-item-text ""
  1045.                   :view-nick-name 'page)
  1046.                 
  1047.                 ))
  1048.  
  1049. (defvar *print-dialog*
  1050.   (make-instance 'print-dialog :window-show nil)
  1051.   "The printing progress dialog box")
  1052.  
  1053. (defmethod get-print-dialog ((self t) &key (display nil) (wait t))
  1054.   (declare (ignore self))
  1055.   "Displays the printer progress dialog box and waits for 1 second."
  1056.   (unless (and *print-dialog* (wptr *print-dialog*) (pointerp (wptr *print-dialog*)))
  1057.     (setq *print-dialog* (make-instance 'print-dialog :window-show nil)))
  1058.   (when (and *printing* display) 
  1059.     (with-focused-view *print-dialog*
  1060.       (window-show *print-dialog*)))
  1061.   (when wait (sleep 1))
  1062.   *print-dialog*)
  1063.  
  1064. ;; default method for removing the print progress dialog box, 
  1065. ;; specialize for other views
  1066. (defmethod remove-print-dialog ((self t))
  1067.   (when (and *print-dialog* (wptr *print-dialog*))
  1068.     (window-close *print-dialog*))
  1069.   (setq *print-dialog* nil))
  1070.  
  1071. ;; default method for indicating printing progress, specialize for other views
  1072. ;; Note: does not update the page field when background printing is off
  1073. (defmethod set-page-number ((self t) page-no &key (display nil))
  1074.   "Update the page number field for printing"
  1075.   (let* ((print-dialog (get-print-dialog self :display display :wait display))
  1076.          (page-field (view-named 'page print-dialog)))
  1077.     ; force the window to be updated
  1078.     (with-focused-view print-dialog
  1079.       (set-dialog-item-text page-field (format nil "~3d" page-no))
  1080.       ;(event-dispatch)    ; fails to return when background printing is off
  1081.       (sleep 1))))
  1082.  
  1083. ;; newer version of set-page-number for laserwriter 8
  1084. #+laserwriter8
  1085. (defmethod set-page-number ((self t) page-no &key (display nil))
  1086.   "Update the page number field for printing"
  1087.   (declare (ignore page-no display)))
  1088.  
  1089. |#            
  1090.  
  1091. ;; methods and functions for working with the printer port as a view
  1092. ;;  similar to the wmgr-view functions in oodles-of-utils:simple-view-ce.lisp
  1093. ;; Supplied by Bill St. Clair at Apple.
  1094.  
  1095. (defclass printer-view (simple-view)
  1096.   ((clip-region :initform nil :accessor printer-view-clip-region)))
  1097.  
  1098. (defmethod view-origin ((view printer-view))
  1099.   (let ((wptr (wptr view)))
  1100.     (if wptr
  1101.       (rref wptr :grafport.portrect.topleft)
  1102.       #@(0 0))))
  1103.  
  1104. (defmethod view-clip-region ((view printer-view))
  1105.   (let ((macptr (printer-view-clip-region view)))
  1106.     (unless (typep macptr 'macptr)
  1107.       (setq macptr
  1108.             (setf (printer-view-clip-region view) (%null-ptr))))
  1109.     (%setf-macptr macptr (rref (wptr view) :grafport.cliprgn))
  1110.     macptr))
  1111.  
  1112. (defun make-printer-view (printer-port)
  1113.   (let ((topleft (rref printer-port :grafport.portrect.topleft))
  1114.         (botright (rref printer-port :grafport.portrect.botright)))
  1115.     (make-instance 'printer-view
  1116.       :wptr printer-port
  1117.       :view-position topleft
  1118.       :view-size (subtract-points botright topleft))))
  1119.  
  1120. ;;  basic macros for using a printer, printing a document and printing a page.
  1121. (defmacro with-open-page ((hardcopy-ptr page-size offset &key (local t))
  1122.                           &rest body)
  1123.   ;; Opens a printer page
  1124.   ;; executes the body
  1125.   ;; closes the printer upon termination (even when in error)
  1126.   ;; returns the result of executing the body
  1127.   (let ((r (gensym))
  1128.         (vals (gensym)))
  1129.     `(let (,vals)
  1130.        (clean-catch-cancel 
  1131.         :open-page
  1132.         (rlet ((,r :rect :topLeft #@(0 0) :bottomRight ,page-size))
  1133.           (when ,local (call-trap 'offsetRect #_offsetRect :ptr ,r :long ,offset))
  1134.           (unwind-protect
  1135.             (clean-catch-cancel 
  1136.              :inner-open-page
  1137.              (setq ,vals
  1138.                    (multiple-value-list
  1139.                     (with-clip-rect ,r 
  1140.                       (check-printer-ok 
  1141.                        (call-trap 'prOpenPage #_PrOpenPage
  1142.                                      :ptr ,hardcopy-ptr :ptr (if ,local ,r  (%null-ptr))))
  1143.                       ,@body))))
  1144.             (check-printer-ok (call-trap 'prClosePage #_PrClosePage :ptr ,hardcopy-ptr)))))
  1145.        (values-list ,vals))))
  1146.  
  1147. (defmacro with-saved-gworld (&rest body)
  1148.   ;; Saves the gworld, executes the body of the code and then restores the gworld
  1149.   ;; upon termination (normal or abnormal)
  1150.   (let ((saved-port (gensym))
  1151.         (saved-device (gensym)))
  1152.     `(with-macptrs (,saved-port ,saved-device)       ; from Bill StClair at Apple
  1153.        (ccl::get-gworld ,saved-port ,saved-device)
  1154.        (flet ((restore-gworld ()
  1155.                 (ccl::set-gworld ,saved-port ,saved-device)))
  1156.          (unwind-protect 
  1157.            (progn ,@body
  1158.                   (restore-gworld))
  1159.            (restore-gworld)   ; from Bill StClair at Apple
  1160.            )))))
  1161.  
  1162. (defmacro with-open-doc (hardcopy-ptr prec &rest body)
  1163.   ; _PrOpenDoc puts up a dialog window
  1164.   ; In order to process events within the body, we must call
  1165.   ; event-dispatch, otherwise windows will not be updated
  1166.   ; Opens the printer document
  1167.   ; Executes the body of code with the local variable
  1168.   ;   hardcopy-ptr bound to the printer GrafPort
  1169.   ;   prec is a handle to the TPrint record
  1170.   ; Closes the printer document upon termination (even when in error)
  1171.   ; Returns the result of executing the body
  1172.   ;;
  1173.   ; without-interrupts appears in the same place as (window-hardcopy fred-window)
  1174.   ; before the open-doc (decinest appears at location 332, open-doc at 360-362)
  1175.   (let ((vals (gensym))
  1176.         (stRec (gensym))
  1177.         (printer-view (gensym)))
  1178.     `(with-saved-gworld
  1179.        (without-interrupts              ; ***bill
  1180.         (let ((,hardcopy-ptr 
  1181.                (call-trap 'prOpenDoc #_PrOpenDoc :ptr ,pRec :ptr (%null-ptr) :ptr (%null-ptr) :ptr))
  1182.               ,vals
  1183.               ,printer-view)
  1184.           (ccl::set-gworld ,hardcopy-ptr)
  1185.           ;***bill (without-interrupts
  1186.           (clean-catch-cancel
  1187.             :open-doc
  1188.             (unwind-protect
  1189.               (clean-catch-cancel
  1190.                 :port
  1191.                 (setq ,printer-view (make-printer-view
  1192.                                      ,hardcopy-ptr))
  1193.                 (check-printer-ok nil $err-printer-start)
  1194.                 (ccl::set-gworld ,hardcopy-ptr)
  1195.                 (setq ,vals
  1196.                       (multiple-value-list
  1197.                        (with-focused-view ,printer-view
  1198.                          ,@body))))
  1199.               (check-printer-ok (progn
  1200.                                   (call-trap 'prCloseDoc #_PrCloseDoc :ptr
  1201.                                                 ,hardcopy-ptr
  1202.                                                 )
  1203.                                   ;; called after #_PrCloseDoc doc <<<<<<<<
  1204.                                   (restore-gworld))))
  1205.             (when (= (href ,prec :tprint.prJob.bjDocLoop)
  1206.                      #$bSpoolLoop)
  1207.               (%stack-block ((,StRec (record-length :tprStatus)))
  1208.                 (check-printer-ok (progn
  1209.                                     (call-trap 'prPicFile #_PrPicFile
  1210.                                                   :ptr ,pRec
  1211.                                                   :ptr (%null-ptr)
  1212.                                                   :ptr (%null-ptr)
  1213.                                                   :ptr (%null-ptr)
  1214.                                                   :ptr ,StRec)
  1215.                                     ;; called after #_PrPicFile doc <<<<<<<<<
  1216.                                     (restore-gworld)))
  1217.                 )))
  1218.           (values-list ,vals))))))
  1219.  
  1220. (defmacro with-open-printer ((prec &key (view t) (show-dialog? nil)) &rest body)
  1221.   ; Opens the printer
  1222.   ; Executes the body of code with the local variable
  1223.   ;  Closes the printer upon termination (even when in error)
  1224.   ;; returns the result of executing the body
  1225.   
  1226.   (let ((vals (gensym))
  1227.         (saved-flags (gensym)))         ; ***bill
  1228.     `(let (,vals ,prec ,saved-flags)
  1229.        (unwind-protect
  1230.          (clean-catch-cancel 
  1231.            :open-print
  1232.            (setq ,vals
  1233.                  (multiple-value-list
  1234.                   (unless *printing*
  1235.                     (check-printer-ok (call-trap 'prOpen #_PrOpen) $err-printer-load)
  1236.                     (setq *printing* t)
  1237.                     (when (and (setq ,prec (get-print-prec ,view))
  1238.                                (check-print-prec ,view)
  1239.                                (or (and (null ,show-dialog?)
  1240.                                         (progn
  1241.                                           (setq ,saved-flags (href ,pRec :tprint.prflag1.flags))        ; ***bill
  1242.                                           (call-trap 'prJobMerge #_prJobMerge :ptr ,pRec :ptr ,pRec)
  1243.                                           (when *debug*
  1244.                                             (print ,prec)
  1245.                                             (print-record ,prec :tprint)
  1246.                                             (terpri))
  1247.                                           t))
  1248.                                    (with-cursor *arrow-cursor*
  1249.                                      (when *debug* (print-record ,prec :tPrint) (terpri))
  1250.                                      (setq ,saved-flags (href ,pRec :tprint.prflag1.flags))        ; ***mark
  1251.                                      (call-trap 'prJobDialog #_PrJobdialog :ptr ,prec :boolean))
  1252.                                    (throw :cancel :cancel)))
  1253.                       ,@body)))))
  1254.          (check-printer-ok (call-trap 'prClose #_PrClose))
  1255.          (when *debug* (print-db ,saved-flags)
  1256.                (print-record ,prec :tPrint) (terpri))
  1257.          (when ,saved-flags             ; ***bill
  1258.            (setf (href ,pRec :tprint.prflag1.flags) ,saved-flags))      ; ***bill
  1259.          (setq *printing* nil))
  1260.        (values-list ,vals))))
  1261.  
  1262. ;; generalized page-setup routines for objects that are not fred windows
  1263. (defmethod page-setup ((self t))
  1264.   ;; Atempts to retrieve a valid tprint handle
  1265.   ;; If successful displays the page setup dialog using the print record
  1266.   ;; Returns t when successful
  1267.   (with-cursor *arrow-cursor*
  1268.     (with-open-printer (prec :view self)
  1269.       (when *debug* (print-record prec :tprint) (terpri))
  1270.       (check-printer-ok (call-trap 'prStlDialog #_PrStlDialog :ptr prec :boolean))
  1271.       (update-file-prec self prec)
  1272.       (when *debug* (print-record prec :tprint) (terpri))
  1273.       t)))
  1274.  
  1275. ;; page setup
  1276. ;;   for fred windows
  1277. (defmethod page-setup ((window fred-window))
  1278.   (let ((*print-record-window* window))
  1279.     (print-style-dialog)))
  1280.  
  1281. ;; Rather than use page-setup, define methods for examining and
  1282. ;; setting printer parameters.
  1283.  
  1284. (defmethod set-print-reduction ((self t) reduction)
  1285.   (with-open-printer (print-record :view self)
  1286.     (if (integerp reduction)
  1287.       (when (macptrp print-record)
  1288.         (let ((min (rref print-record :tprint.izoommin))
  1289.               (max (rref print-record :tprint.izoommax)))
  1290.           (if (<= min reduction max)
  1291.             (rset print-record :tprint.prxinfo.ibandh reduction)
  1292.             (error "~s must be between ~d and ~d" reduction min max))))
  1293.       (error "~s must be an integer" reduction))))
  1294.  
  1295. (defmethod get-print-reduction ((self t))
  1296.   (with-open-printer (print-record :view self)
  1297.     (if (macptrp print-record)
  1298.       (rref print-record :tprint.prxinfo.ibandh)
  1299.       (error "~s is not a macintosh pointer" print-record))))
  1300.  
  1301. (defmethod set-print-orientation ((self t) orientation)
  1302.   ;; orientation is either :landscape or :portrait
  1303.   (with-open-printer (print-record :view self)
  1304.     (when (macptrp print-record)
  1305.       (let* ((old (rref print-record :tprint.prstl.wdev))
  1306.              (old-orientation (ldb (byte 1 1) old))
  1307.              (bit (case orientation
  1308.                     (:landscape 0)
  1309.                     (:portrait 1)))
  1310.              ;; experimentally determined that bit one controls orientation
  1311.              ;; is this always true?
  1312.              new)
  1313.         (when bit
  1314.           (setq new (dpb bit (byte 1 1) old)))
  1315.         (unless (= old-orientation bit)
  1316.           (reverse-page-dimensions print-record)
  1317.           (rset print-record :tprint.prstl.wdev new))))))
  1318.  
  1319. (defmethod get-print-orientation ((self t))
  1320.   (with-open-printer (print-record :view self)
  1321.     (when (macptrp print-record)
  1322.       (case (ldb (byte 1 1)
  1323.                  (rref print-record :tprint.prstl.wdev))
  1324.         (0 :landscape)
  1325.         (1 :portrait)))))
  1326.  
  1327. (defun reverse-point (point)
  1328.   (make-point (point-v point) (point-h point)))
  1329.  
  1330. (defmacro reverse-a-page-field (print-record field)
  1331.   `(rset ,print-record ,field
  1332.          (reverse-point (href ,print-record ,field))))
  1333.  
  1334. (defun reverse-page-dimensions (print-record)
  1335.   (reverse-a-page-field print-record :tprint.prinfo.rpage.topLeft)
  1336.   (reverse-a-page-field print-record :tprint.prinfo.rpage.bottomRight)
  1337.   (reverse-a-page-field print-record :tprint.rpaper.topLeft)
  1338.   (reverse-a-page-field print-record :tprint.rpaper.bottomRight)
  1339.   (reverse-a-page-field print-record :tprint.prinfopt.rpage.topLeft)
  1340.   (reverse-a-page-field print-record :tprint.prinfopt.rpage.bottomRight))
  1341.  
  1342. (defmethod get-print-page ((self t))
  1343.   (with-open-printer (print-record :view self)
  1344.     (when (macptrp print-record)
  1345.       (values
  1346.        (point-string (href print-record :tprint.prinfo.rpage.topLeft))
  1347.        (point-string (href print-record :tprint.prinfo.rpage.bottomRight))
  1348.        (point-string (href print-record :tprint.rpaper.topLeft))
  1349.        (point-string (href print-record :tprint.rpaper.bottomRight))
  1350.        (point-string (href print-record :tprint.prinfopt.rpage.topLeft))
  1351.        (point-string (href print-record :tprint.prinfopt.rpage.bottomRight))))))
  1352.  
  1353. ;; routines for determining the topLeft and bottomRight corners
  1354. ;; of the printer-page
  1355. (defun get-page-size (pRec)
  1356.   (subtract-points (href pREC :tprint.prInfo.rpage.bottomRight)
  1357.                    (href pREC :tprint.prInfo.rpage.topLeft)))
  1358.  
  1359. (defmethod page-size ((self t))
  1360.   (with-open-printer (prec :view self)
  1361.     (get-page-size prec)))
  1362.  
  1363. (defmethod page-size ((window fred-window))
  1364.   (with-open-printer (prec :view window)
  1365.     (get-page-size prec)))
  1366.      
  1367. ;; Routines for computing the corners of rectangular pictures and windows
  1368.  
  1369. (defun picture-corners (picture page-size)
  1370.   (declare (ignore page-size))
  1371.   ;; return the topleft and bottomRight corners of the picture
  1372.   (when (handlep picture)
  1373.     (values
  1374.      (rref picture picture.picframe.topleft)
  1375.      (rref picture picture.picframe.bottomRight))))
  1376.  
  1377. (defmethod window-document-corners ((view window) page-size)
  1378.   (declare (ignore page-size))
  1379.   ;; Computes the topLeft and bottomRight corners of the rectangle
  1380.   ;; for the view. Specialize to handle scrolling windows
  1381.   (view-corners view))
  1382.  
  1383. (defmethod view-document-corners ((view view) page-size)
  1384.   (declare (ignore page-size))
  1385.   ;; Computes the topLeft and bottomRight corners of the rectangle
  1386.   ;; for the view. Specialize to handle scrolling windows
  1387.   (view-corners view))
  1388.  
  1389. ;; routines for computing the page layout (document size in pages-h x pages-v)
  1390. (defun compute-page-size (document-size page-size)
  1391.   ;; returns the point representing the document-size in pages width x depth
  1392.   (let* ((page-h (ceiling (point-h document-size) (point-h page-size)))
  1393.          (page-v (ceiling (point-v document-size) (point-v page-size))))
  1394.     (values
  1395.      page-h
  1396.      page-v
  1397.      (* page-h page-v))))
  1398.  
  1399. ;; not currently used, can be used within the print-fn for a document-hardcopy
  1400. ;; to determine the current page number, and row/column index
  1401. (defun compute-page-topLeft (page-size pages-h pages-v page-no)
  1402.   ;; given the size of the page-rectangle (page-size)
  1403.   ;;       the dimensions of the document in pages pages-h x pages-v
  1404.   ;;       the page number being printed
  1405.   ;; returns the page-no and the column/row position of the page
  1406.   ;;       and the coordinates of the upper left corner of the
  1407.   ;;       document corresponding to the page of size page-size
  1408.   (declare (ignore pages-v))
  1409.   (multiple-value-bind (real-v real-h)
  1410.                        (truncate page-no pages-h)
  1411.     (values
  1412.      page-no
  1413.      real-h
  1414.      real-v
  1415.     (make-point (* (point-h page-size) real-h)
  1416.                 (* (point-v page-size) real-v)))))
  1417.  
  1418. ;; default routines for printing a document and for determining its size
  1419. (defun default-document-hardcopy (view page-size page-no offset local)
  1420.   (declare (ignore view prRec page-size page-no offset local)))
  1421.  
  1422. (defun default-document-corners (view psize)
  1423.   (declare (ignore view))
  1424.   (values #@(0 0) psize))
  1425.  
  1426. (defun compute-page-layout (view page-size compute-doc-size)
  1427.   ;; uses the compute-doc-size function with view and page-size
  1428.   ;; to compute the size of the document in pages (pages-h x pages-v)
  1429.     (multiple-value-bind (top bottom)
  1430.                          (funcall (if (functionp compute-doc-size)
  1431.                                     compute-doc-size
  1432.                                     #'ccl::default-document-corners)
  1433.                                   view page-size)
  1434.       (compute-page-size (subtract-points bottom top) page-size)))
  1435.  
  1436.  
  1437. ;; hardcopy routines for documents, windows and pictures
  1438.  
  1439. ;;  General hardcopy routine
  1440. (defun document-hardcopy (print-fn document-corners &key (show-dialog? t) view (local t))
  1441.   (setq *print-error* nil)
  1442.   (let (offset
  1443.         ;progress
  1444.         page-size v-dim h-dim (page-no 0))
  1445.     ;(setq progress (get-print-dialog view))
  1446.     (with-cursor *arrow-cursor* 
  1447.       (with-open-printer (prec :view view :show-dialog? show-dialog?)
  1448.         (with-cursor *watch-cursor*
  1449.           (when *printing*
  1450.             (clean-catch-cancel 
  1451.              :doco
  1452.               (unwind-protect
  1453.                 (setq page-size (get-page-size prec))
  1454.                 (multiple-value-bind (pages-h pages-v pages)
  1455.                                      (compute-page-layout view page-size document-corners)
  1456.                   (decf pages-h)
  1457.                   (decf pages-v)
  1458.                   (unless (functionp print-fn)
  1459.                     (setq print-fn #'default-document-hardcopy))
  1460.                   ;(when (setq progress (get-print-dialog view :display t))
  1461.                     ;(window-select progress)
  1462.                     ;(event-dispatch))
  1463.                   (with-open-doc hardcopy-ptr prec
  1464.                     (let* ((from-page (max 1 (href prec :tprint.prJob.iFstPage)))
  1465.                            (to-page (min pages (href prec :tprint.prJob.iLstPage)))
  1466.                            (pages-to-print (1+ (- to-page from-page))))
  1467.                       ;; print pages-to-print pages (from from-page to to-page)
  1468.                       ;; adjust the print record to print only pages-to-print pages
  1469.                       (set-page-range prec pages-to-print)
  1470.                       (loop for v-page fixnum from 0 to pages-v
  1471.                             do (setq v-dim (* (point-v page-size) v-page))
  1472.                             (loop for h-page fixnum from 0 to pages-h
  1473.                                   do (incf page-no)
  1474.                                   (when (<= from-page page-no to-page)
  1475.                                     ;; only print pages in the range from-page to to-page
  1476.                                     (decf pages-to-print)
  1477.                                     (when *debug* (print-db pages-to-print))
  1478.                                     (setq h-dim (* (point-h page-size) h-page))
  1479.                                     (setq offset (make-point h-dim v-dim))
  1480.                                     (when *printing*
  1481.                                       ;(set-page-number view page-no :display t)
  1482.                                       (with-open-page (hardcopy-ptr page-size offset :local local)
  1483.                                         (funcall print-fn view page-size page-no offset local))))
  1484.                                   
  1485.                                   while (and *printing*   ; stop when printing canceled
  1486.                                              (> pages-to-print 0)))   ; or no pages to print
  1487.                             
  1488.                             ; stop when no pages remain to print or printing is cancelled
  1489.                             while (and *printing* (> pages-to-print 0)))))))))
  1490.           (unless *printing* 
  1491.             (unless *print-error*
  1492.               (setq *print-error* (make-condition 'printer-condition))
  1493.               (with-slots (phase code cond) *print-error*
  1494.                 (setq phase $err-printer
  1495.                       code #$iPrAbort
  1496.                       cond nil))
  1497.               (call-trap 'prsetError #_PrSetError #$iPrAbort)))
  1498.           ;(remove-print-dialog view)
  1499.           (setq *printing* nil)
  1500.           (null *print-error*))))))
  1501.  
  1502. ;; Internal routine for printing the contents of a views
  1503. (defmethod view-print-contents ((subview view)
  1504.                                 page-size page-no offset local)
  1505.   (declare (ignore page-size page-no))
  1506.   (let ((*print-record-window* subview))
  1507.     (print-contents subview (if local #@(0 0)
  1508.                                 offset))))
  1509.  
  1510. ;; Print contents of a non-fred window, fred windows already defined
  1511. (defmethod window-hardcopy ((v window) &optional (show-dialog? t))
  1512.   (document-hardcopy #'view-print-contents #'window-document-corners
  1513.                      :view  v
  1514.                      :show-dialog? show-dialog?
  1515.                      :local t))
  1516.  
  1517. ;; Print a picture on the printer
  1518. (defun picture-hardcopy (picture &optional (show-dialog? t))
  1519.   (when (handlep picture)
  1520.     (with-dereferenced-handles ((picture-ptr picture))
  1521.       (flet ((pict-draw (view page-size page-no offset local)
  1522.                (declare (ignore view page-no))
  1523.                (multiple-value-bind (topLeft bottomRight)
  1524.                                     (picture-corners picture page-size)
  1525.                  (with-rectangle-arg (r topLeft bottomRight)
  1526.                    (unless local (call-trap 'offsetRect #_offsetRect :ptr r :long (subtract-points #@(0 0) offset)))
  1527.                    (call-trap 'drawPicture #_drawPicture :ptr picture :ptr r))))
  1528.              (pict-size (view page-size)
  1529.                (declare (ignore view))
  1530.                (picture-corners picture page-size)))
  1531.         (declare (dynamic-extent #'pict-draw #'pict-size))
  1532.         (document-hardcopy #'pict-draw #'pict-size :show-dialog? show-dialog?)))))
  1533.  
  1534.  
  1535. ;;;; functions to setup the environment for printing
  1536. ;; changes the page setup menu item to use the new Page Setup function
  1537. (defun fix-file-menu ()
  1538.   (let ((page-setup (find-menu-item *file-menu* "Page Setup"))
  1539.         (print (find-menu-item *file-menu* "Print")))
  1540.     (when page-setup
  1541.       (change-class page-setup 'window-menu-item)
  1542.       (setf (menu-item-action-function page-setup)
  1543.             #'(lambda (window)
  1544.                 (eval-enqueue `(page-setup ,window)))))
  1545.     (when print
  1546.       (setf (menu-item-action-function print)
  1547.             #'(lambda (window)
  1548.                 (eval-enqueue `(ccl::window-hardcopy ,window)))))
  1549.     (setq *printing* nil)))
  1550.  
  1551. (defun remove-hc-prec ()
  1552.   ;; clean up the internal tprint handle
  1553.   ;; modify if you need to clean up others
  1554.   (remove-prec t))
  1555.                 
  1556. (defun setup-printing ()
  1557.   ;; remove and then add #'fix-file-menu to end of *lisp-startup-functions*
  1558.   (setq *lisp-startup-functions*
  1559.         (remove 'fix-file-menu *lisp-startup-functions* :key #'function-name))
  1560.   (setq *printing* nil)
  1561.   (push #'fix-file-menu *lisp-startup-functions*)
  1562.   (setq *save-exit-functions*
  1563.         (remove 'remove-hc-prec *save-exit-functions* :key #'function-name))
  1564.   (push #'remove-hc-prec *save-exit-functions*))
  1565.  
  1566. ;; Routines for changing the line width for PostScript devices
  1567. ;;  Routines can be used to build pictures
  1568. ;;  or within a document-hardcopy
  1569. ;; The routines change the printed output only for PostScript devices
  1570. ;; 
  1571. ;;  
  1572. (defun scale-line-width (scale)
  1573.   (unless (rationalp scale)
  1574.     (error "~A is not a Rational" scale))
  1575.   (let ((h (denominator scale))
  1576.         (v (numerator scale)))
  1577.     (let ((width-h (call-trap 'newHandle #_NewHandle (record-length :fixedPoint))))
  1578.       (unless (valid-handle width-h)
  1579.         (error "unable to allocate a ~a temporary record handle (~a bytes)."
  1580.                (record-length :fixedPoint)))
  1581.       (unwind-protect
  1582.         (progn
  1583.           (with-dereferenced-handles ((width-p width-h))
  1584.             (call-trap 'setPt #_setpt (:pointer :point) width-p 
  1585.                           :signed-integer h 
  1586.                           :signed-integer v))
  1587.           (call-trap 'picComment #_piccomment :word $set-line-width :word 4 :ptr width-h))
  1588.         (dispose-handle width-h)))))
  1589.  
  1590. (defun normal-line-width ()
  1591.   (scale-line-width 1))
  1592.   
  1593. ;; setup the printing enviroment and fix the Page setup menu item
  1594. (setup-printing)
  1595. (fix-file-menu)
  1596.  
  1597. ;; augment the window-hardcopy, window-save, print-style-dialog
  1598. ;; and get-print-record routines
  1599. (advise ccl::window-hardcopy
  1600.         (let* ((*print-record-window* (car arglist))
  1601.                (*hc-prec* (with-open-printer (prec :view *print-record-window*)
  1602.                             (get-print-prec *print-record-window*))))
  1603.           (:do-it))
  1604.         :when :around)
  1605.  
  1606. (advise ccl::window-save-file
  1607.         (let ((*print-record-window* (car arglist))
  1608.               window-file)
  1609.           (setq window-file (:do-it))
  1610.           (when window-file
  1611.             (with-open-printer (prec :view *print-record-window*)
  1612.               (get-print-prec *print-record-window*)
  1613.               (update-file-prec *print-record-window* 
  1614.                            (get-prec *print-record-window*)
  1615.                            window-file)))
  1616.           window-file)
  1617.         :when :around)
  1618.  
  1619. (advise ccl::print-style-dialog
  1620.         (let ((*print-record-window* (front-window))
  1621.               result)
  1622.           (setq result (:do-it))
  1623.           (with-open-printer (prec :view *print-record-window*)
  1624.             (get-print-prec *print-record-window*)
  1625.             (update-file-prec *print-record-window* (prec-get *print-record-window*)))
  1626.           result)
  1627.         :when :around)
  1628.  
  1629. (let ((*warn-if-redefine* nil)
  1630.       (*warn-if-redefine-kernel* nil))
  1631.   
  1632.   (defun get-print-record ()
  1633.     (if *print-record-window*
  1634.       (get-prec *print-record-window*)
  1635.       (funcall *mcl-get-print-record*)))
  1636.   
  1637.   )
  1638.  
  1639.  
  1640. #|
  1641. (defun make-print-demo ()
  1642.   "Create the experiment application"
  1643.   (let ((target-appl (choose-new-file-dialog :directory "ccl;print-demo")))
  1644.     (save-application target-appl
  1645.                       :excise-compiler nil    ; do want the compiler
  1646.                       :creator :glop
  1647.                       :clear-clos-caches nil ; otherwise we can't access classes
  1648.                       )))
  1649. (make-print-demo)
  1650. |#
  1651.  
  1652. #|
  1653. ;;;  Four printing examples and two examples of saving private print records
  1654. ;;;
  1655. ;;;  Five printing examples:
  1656. ;;;  - contents of a small window
  1657. ;;;  - a picture
  1658. ;;;  - contents of a large window
  1659. ;;;  - a general document
  1660. ;;;  - a window with a view-draw-contents method that calls a print-contents method
  1661.  
  1662. (defvar *w1*)
  1663. (defvar *test-window*)
  1664. (defvar *picture*)
  1665. (require 'quickdraw)
  1666.  
  1667.  
  1668. ;;---------------------- printing the contents of a small window ------------------------
  1669. ;; Create a window with nested views and print it.
  1670. (setq *w1* (make-instance 'window
  1671.             :window-title "HI there"
  1672.             :view-size #@(300 300)
  1673.             :view-subviews
  1674.                (list (make-instance 'view
  1675.                    :view-position #@(20 20)
  1676.                    :view-size #@(150 130)
  1677.                    :view-subviews
  1678.                        (List (make-instance 'static-text-dialog-item
  1679.                                  :view-position #@(10 10)
  1680.                                  :view-size #@(130 40)
  1681.                                  :view-font '("Helvetica" :srcor :bold 12)
  1682.                                  :dialog-item-text
  1683.                                     "how now said the big brown cow")
  1684.                              (make-instance 'static-text-dialog-item
  1685.                                             :view-position #@(10 70)
  1686.                                             :view-size #@(130 60)
  1687.                                             :view-font '("Geneva" :srcor :underline 14)
  1688.                                             :dialog-item-text
  1689.                                             "there is a bunch of green cheese here on the moon")))
  1690.                      (make-instance 'button-dialog-item
  1691.                                             :view-position #@(160 160)
  1692.                                             :view-size #@(72 16)
  1693.                                             :dialog-item-text "Green"))))
  1694.  
  1695. (window-hardcopy *w1*)                  ; print the window
  1696.                                         ; Also select the window and do a file Print
  1697.  
  1698. ;;---------------------------- printing a picture -----------------------------
  1699. ;; Print a picture. The picture corresponds to a picture of the print-contents
  1700. ;; of the window w1 using a window twice the size. 
  1701. (let ((view-size (view-size *w1*)) mid-point)
  1702.   (when (and (boundp '*picture*) (handlep *picture*))
  1703.     (kill-picture *picture*))
  1704.   (with-focused-view *w1*
  1705.     (start-picture *w1* #@(0 0) (make-point (* 2 (point-h view-size))
  1706.                                             (* 2 (point-v view-size))))
  1707.     (print-contents *w1*)
  1708.     (setq *picture* (get-picture *w1*)))
  1709.  
  1710.   ;; draw the picture at half- in the bottom right corner of *w1*
  1711.   (window-select *w1*)
  1712.   (sleep 1)
  1713.   (setq mid-point (make-point (floor (point-h view-size) 2)
  1714.                               (floor (point-v view-size) 2)))
  1715.   (draw-picture *w1* *picture* mid-point (add-points (view-size *w1*) mid-point))
  1716.   (sleep 1)
  1717.   (print-record *picture* :picture) (terpri)
  1718.   (picture-hardcopy *picture*)              ; print the picture
  1719.   (kill-picture *picture*)                  ; remove the picture
  1720.   )
  1721.  
  1722.  
  1723. ;;;  - 
  1724. ;;-------------------- printing the contents of a large window ---------------------
  1725. ;;  Print the contents of a large dialog (918 x 708) 
  1726. (setq *test-window*
  1727.    (make-instance 'color-dialog
  1728.                :window-type :document-with-zoom 
  1729.                :view-position #@(100 100)
  1730.                :view-size #@(918 708)
  1731.                :view-font '("Chicago" 12 :SRCOR :PLAIN)
  1732.                :view-subviews
  1733.                (list (make-instance 'static-text-dialog-item
  1734.                                        :view-position #@(13 9)
  1735.                                        :view-size #@(56 16)
  1736.                                        :dialog-item-text "Untitled")
  1737.  
  1738.                      (make-instance 'editable-text-dialog-item
  1739.                                        :view-position #@(15 25)
  1740.                                        :view-size #@(84 16)
  1741.                                        :dialog-item-text "Untitled"
  1742.                                        :allow-returns nil)
  1743.  
  1744.                      (make-instance 'button-dialog-item
  1745.                                        :view-position #@(15 47)
  1746.                                        :view-size #@(62 16)
  1747.                                        :dialog-item-text "Untitled"
  1748.                                        :default-button nil)
  1749.  
  1750.                      (make-instance 'editable-text-dialog-item
  1751.                                        :view-position #@(381 683)
  1752.                                        :view-size #@(114 16)
  1753.                                        :dialog-item-text "bottom center"
  1754.                                        :allow-returns nil)
  1755.  
  1756.                      (make-instance 'editable-text-dialog-item
  1757.                                        :view-position #@(11 688)
  1758.                                        :view-size #@(84 16)
  1759.                                        :dialog-item-text "bottom left"
  1760.                                        :allow-returns nil)
  1761.  
  1762.                      (make-instance 'editable-text-dialog-item
  1763.                                        :view-position #@(375 20)
  1764.                                        :view-size #@(84 16)
  1765.                                        :dialog-item-text "top center"
  1766.                                        :allow-returns nil)
  1767.  
  1768.                      (make-instance 'editable-text-dialog-item
  1769.                                        :view-position #@(799 676)
  1770.                                        :view-size #@(84 16)
  1771.                                        :dialog-item-text "bottom right"
  1772.                                        :view-font
  1773.                                        '("New Century Schlbk"
  1774.                                          12 :SRCOR :PLAIN)
  1775.                                        :allow-returns nil)
  1776.  
  1777.                      (make-instance 'editable-text-dialog-item
  1778.                                        :view-position #@(818 20)
  1779.                                        :view-size #@(84 16)
  1780.                                        :dialog-item-text "top right"
  1781.                                        :view-font
  1782.                                        '("New Century Schlbk"
  1783.                                          12 :SRCOR :PLAIN)
  1784.                                        :allow-returns nil)))
  1785. )
  1786.  
  1787. (window-hardcopy *test-window*)           ; print the large dialog
  1788.  
  1789. ;;---------------------- printing a general document -----------------------
  1790. ;;  Print a document of size 552 x 1460 pixels
  1791. ;;  This requires two 8.5" x 11" pages at normal size (Reduce/Enlarge 100%)
  1792. ;;  At normal size prints two pages with 
  1793. ;;  "Now is the time for all good men to come to the aid" on the first page
  1794. ;;  twice on the first page at #@(50 50) and #@(50 100)
  1795. ;;  and with the string "When johnny comes marching home again" in the
  1796. ;;  relative positions #@(200 0) and #@(50 100) on the second page.
  1797. ;;  At 50% or smaller reduction, prints only the first page, reduced.
  1798. ;;  At 200% or greater reduction prints two pages, enlarged.
  1799.  
  1800. ;;  When 50% reduction, prints only one "page"
  1801. (defun my-hardcopy-fn (view page-size page-no offset local)
  1802.   (declare (ignore view page-size))
  1803.   (unless local (setq offset #@(0 0)))
  1804.   (let ((text "Now is the time for all good men to come to the aid"))
  1805.     (with-font-spec '("Times" 18 :srcor :plain)
  1806.       (if (= page-no 0)
  1807.         (call-trap #_moveTo :long (add-points #@(50 50) offset))
  1808.         (progn (call-trap #_moveTo :long (add-points #@(200 0) offset))
  1809.                (setq text "When johnny comes marching home again")))
  1810.       (with-returned-pstrs ((text-buff text))
  1811.         (call-trap #_DrawText :ptr text-buff :integer 1 :integer (length text)))
  1812.       (call-trap #_moveTo :long (add-points #@(50 100) offset))
  1813.       (with-returned-pstrs ((text-buff text))
  1814.         (call-trap #_DrawText :ptr text-buff :integer 1 :integer (length text)))
  1815.       )))
  1816.  
  1817. (defun my-document-corners (view page-size)
  1818.   (declare (ignore view page-size))
  1819.   ;; a document on 8.5 x 11 paper 1 wide and 2 high
  1820.   (values #@(0 0) (make-point 552 (* 2 730))))
  1821.  
  1822. (document-hardcopy #'my-hardcopy-fn #'my-document-corners)   ; print the document
  1823.  
  1824. ;;-------------------- a window with a view-draw-contents calling print-contents -----------
  1825. (defclass my-window (window) nil
  1826.   (:default-initargs :window-title "*print me*"))
  1827. (defvar *win*)
  1828.  
  1829. ;; this method does not work - the commands do not appear in the postscript file 
  1830. (defmethod view-draw-contents ((window my-window))
  1831.   (with-focused-view window
  1832.     (#_moveto 0 0)
  1833.     (#_lineto 100 0)
  1834.     (#_lineto 100 200)
  1835.     (#_lineto 0 200)
  1836.     (#_lineto 0 0)
  1837.     (#_lineto 100 200)
  1838.     (#_lineto 200 0)
  1839.     (#_lineto 300 50)))
  1840.  
  1841. ;; the commands appear in the postscript file 
  1842. (defmethod view-draw-contents ((window my-window))
  1843.   (with-focused-view window
  1844.     (display-contents window)))
  1845.  
  1846. (defmethod display-contents ((window my-window))
  1847.     (#_moveto 10 10)
  1848.     (#_lineto 100 10)
  1849.     (#_lineto 100 200)
  1850.     (#_lineto 10 200)
  1851.     (#_lineto 10 10)
  1852.     (#_lineto 100 200)
  1853.     (#_lineto 200 0)
  1854.     (#_lineto 300 50))
  1855.  
  1856. (defmethod print-contents ((window my-window) &optional (offset #@(0 0)))
  1857.   (declare (ignore offset))
  1858.   (call-next-method)
  1859.   (display-contents window))
  1860.  
  1861. (setq *win* (make-instance 'my-window
  1862.               :view-size #@(400 400)))
  1863. ;; (window-close *win*)
  1864. ;;;  - 
  1865. ;;-------------------- changing the page setup atributes of a file ---------------------
  1866. ;; open an existing file in a fred window,
  1867. ;; change the page setup attributes and reopen the file 
  1868. (defvar *test-window*)
  1869. (defvar *file-name*)
  1870. (setq *test-window* (fred (choose-file-dialog :button-string "Edit")))
  1871. (setq *file-name* (view-file-name *test-window*))
  1872.  
  1873. ;; Change the page setup   
  1874. (page-setup *test-window*)
  1875. (window-close *test-window*)
  1876.  
  1877. ;; open the file again and see that the attributes have changed
  1878. (setq *test-window* (fred *file-name*))
  1879. (page-setup *test-window*)
  1880.  
  1881. ;; open the file and see that the :prec resource has been saved
  1882. (with-open-resource-file (refnum *file-name* :if-does-not-exist nil)
  1883.   (let (printer-record)
  1884.     (setq printer-record (get-resource :prec 128 :errorp nil))
  1885.     (print-db printer-record)
  1886.     (when (valid-handle printer-record)
  1887.       (print-record printer-record :tprint))))
  1888.  
  1889. ;;;  - 
  1890. ;;-------------------- views that store their print record in a slot ---------------------
  1891. ;;  the slot is ccl::my-print-record
  1892.  
  1893. (defclass print-view (view)
  1894.   ((my-print-record :initform nil)
  1895.    (my-file-name :initform nil)))
  1896.  
  1897. (defclass print-window (print-view window) nil)
  1898.  
  1899. (defmethod view-file-name ((view print-view))
  1900.   (slot-value view 'my-file-name))
  1901.  
  1902. (defmethod view-get ((view print-view) flag &optional option)
  1903.   (declare (ignore option))
  1904.   (if (equal flag :prec)
  1905.       (slot-value view 'my-print-record)
  1906.       (call-next-method)))
  1907.  
  1908. (defmethod view-put ((view print-view) flag value)
  1909.   (if (equal flag :prec)
  1910.     (setf (slot-value view 'my-print-record) value)
  1911.     (call-next-method)))
  1912.  
  1913. (setq *test-window* (make-instance 'print-window))
  1914. (setq *file-name* (choose-file-dialog))
  1915.  
  1916. ;; change the page setup attributes, they'll be saved with the file
  1917. (page-setup *test-window*)
  1918. (window-close *test-window*)
  1919.  
  1920. ;; create another window into the same "file"
  1921. ;; and see that the print-record has been restored.
  1922. (setq *test-window* (make-instance 'print-window))
  1923. (setf (slot-value *test-window* 'my-file-name) *file-name*)
  1924. (page-setup *test-window*)
  1925.  
  1926.  
  1927. ;;;  - 
  1928. ;;-------------------- printing pictures with different line widths ---------------------
  1929.  
  1930. An example which creates two pictures, displays both at 400% scale,
  1931. and prints them.
  1932.  
  1933. Assumptions:
  1934.    The display device has a horizontal/vertical resolution of 72 pixels/inch
  1935.    The PostScript device resolution is 300 pixels/inch.
  1936.    The PageSetup is normal
  1937.        no enlargement/reduction
  1938.        no precision bit map 
  1939.        etc.
  1940.  
  1941. Each picture is the result of drawing a line of size #@(1 1)
  1942. from #@(0 0) to #@(100 100),coinciding with two corners of
  1943. the picture rectangle.
  1944.  
  1945. When the first picture is printed, the lines are normal size.
  1946. When the second picture is printed, the lines are hairline 1/4 thickness.
  1947.  
  1948.                     ; use quickdraw routines
  1949. (let (that
  1950.       new-picture)
  1951.   (eval-when (eval load compile)
  1952.     (require :quickdraw))
  1953.   (setq that (make-instance 'window))
  1954.   (window-select that)
  1955.   (set-view-size that 400 400)
  1956.   (loop for scaling in '(nil t)
  1957.         do(progn
  1958.             (with-focused-view that
  1959.               (start-picture that 0 0 100 100)
  1960.               (when scaling
  1961.                 (scale-line-width 1/4))
  1962.               (call-trap #_moveto 0 0)
  1963.               (call-trap #_lineto 100 50)
  1964.               (when scaling
  1965.                 (normal-line-width)))
  1966.             (setq new-picture (get-picture that))
  1967.             (draw-picture that new-picture 0 0 400 400)
  1968.             (picture-hardcopy new-picture)
  1969.             (kill-picture new-picture)))
  1970.   (window-close that))
  1971.  
  1972.  
  1973. Here's the end of the PostScript code corresponding to the first picture
  1974.  
  1975. T T 0 0 730 552 -31 -30 761 582 100 72 72 1 F F F F T T T F psu
  1976. (LARRY     Ecstatic; document: Untitled)jn
  1977. 0 mf
  1978. od
  1979. %%EndDocumentSetup
  1980. %%Page: ? 1
  1981. op
  1982. 0 0 730 552 fr
  1983. 0 0 xl
  1984. 1 1 pen
  1985. 0 0 gm
  1986. (nc 0 0 100 100 6 rc)kp
  1987. 50 100 lin
  1988. F T cp
  1989. %%Trailer
  1990. cd
  1991. end
  1992. %%Pages: 1 0
  1993. %%EOF
  1994.  
  1995. Here's the end of the PostScript code corresponding to the second picture
  1996.  
  1997. T T 0 0 730 552 -31 -30 761 582 100 72 72 1 F F F F T T T F psu
  1998. (LARRY     Ecstatic; document: Untitled)jn
  1999. 0 mf
  2000. od
  2001. %%EndDocumentSetup
  2002. %%Page: ? 1
  2003. op
  2004. 0 0 730 552 fr
  2005. 0 0 xl
  2006. 1 1 pen
  2007. 0 0 gm
  2008. (nc 0 0 0 0 6 rc)kp
  2009. 1 4 lw
  2010. (nc 0 0 100 100 6 rc)kp
  2011. 50 100 lin
  2012. 1 1 lw
  2013. F T cp
  2014. %%Trailer
  2015. cd
  2016. end
  2017. %%Pages: 1 0
  2018. %%EOF
  2019.  
  2020. |#
  2021. ;;; end of file